/*
 * PROJECT:     ReactOS API tests
 * LICENSE:     MIT (https://spdx.org/licenses/MIT)
 * PURPOSE:     Tests for exp
 * COPYRIGHT:   Copyright 2021 Timo Kreuzer <timo.kreuzer@reactos.org>
 */

#if !defined(_CRTBLD) && !defined(_M_IX86)
#define _CRTBLD // we don't want inline exp!
#endif
#include "math_helpers.h"

#ifdef _MSC_VER
#pragma function(exp)
#endif

#if !defined(_M_IX86)
#define HAS_EXPF
#elif (defined(TEST_UCRTBASE) || defined(TEST_STATIC_CRT))
#define HAS_LIBM_SSE2
#endif


// These are expected to match exactly
static TESTENTRY_DBL s_exp_exact_tests[] =
{
    { 0x0000000000000000 /*  0.000000 */, 0x3ff0000000000000 /*  1.000000 */ },
    { 0x8000000000000000 /* -0.000000 */, 0x3ff0000000000000 /*  1.000000 */ },
    { 0x7ff0000000000000 /*  1.#INF00 */, 0x7ff0000000000000 /*  1.#INF00 */ },
    { 0x7ff7ffffffffffff /*  1.#SNAN0 */, 0x7fffffffffffffff /*  1.#QNAN0 */ },
    { 0x7ff8000000000000 /*  1.#QNAN0 */, 0x7ff8000000000000 /*  1.#QNAN0 */ },
    { 0x7fffffffffffffff /*  1.#QNAN0 */, 0x7fffffffffffffff /*  1.#QNAN0 */ },
    { 0xfff0000000000000 /* -1.#INF00 */, 0x0000000000000000 /*  0.000000 */ },
    { 0xfff7ffffffffffff /* -1.#SNAN0 */, 0xffffffffffffffff /* -1.#QNAN0 */ },
    { 0xfff8000000000000 /* -1.#IND00 */, 0xfff8000000000000 /* -1.#IND00 */ },
    { 0xffffffffffffffff /* -1.#QNAN0 */, 0xffffffffffffffff /* -1.#QNAN0 */ },
#ifdef _M_IX86
    { 0x7ff0000000000001 /*  1.#SNAN0 */, 0x7ff8000000000000 /*  1.#QNAN0 */ },
    { 0x7ff8000000000001 /*  1.#QNAN0 */, 0x7ff8000000000000 /*  1.#QNAN0 */ },
    { 0xfff0000000000001 /* -1.#SNAN0 */, 0xfff8000000000000 /* -1.#QNAN0 */ },
    { 0xfff8000000000001 /* -1.#QNAN0 */, 0xfff8000000000000 /* -1.#QNAN0 */ },
#else
    { 0x7ff0000000000001 /*  1.#SNAN0 */, 0x7ff8000000000001 /*  1.#QNAN0 */ },
    { 0x7ff8000000000001 /*  1.#QNAN0 */, 0x7ff8000000000001 /*  1.#QNAN0 */ },
    { 0xfff0000000000001 /* -1.#SNAN0 */, 0xfff8000000000001 /* -1.#QNAN0 */ },
    { 0xfff8000000000001 /* -1.#QNAN0 */, 0xfff8000000000001 /* -1.#QNAN0 */ },
#endif
};

void Test_exp_exact(void)
{
    for (int i = 0; i < _countof(s_exp_exact_tests); i++)
    {
        double x = u64_to_dbl(s_exp_exact_tests[i].x);
        double z = exp(x);
        ok_eq_dbl_exact("exp", s_exp_exact_tests[i].x, z, s_exp_exact_tests[i].result);
    }
}

// This table is autogenerated by `python gen_math_tests.py exp`
static TESTENTRY_DBL_APPROX s_exp_approx_tests[] =
{
//  {    x,                     {    y_rounded,               y_difference           } }
    {    -0x1.9000000000000p+6, {   0x1.a8c1f14e2af5dp-145,  -0x1.43089bb228e2cp-199 }, 1 }, // exp(-100.0) == 3.720075976020835963e-44
    {    -0x1.839cccccccccdp+6, {   0x1.25baa29e5bef2p-140,   0x1.0fef0fd797a7ap-194 }, 1 }, // exp(-96.903125) == 8.2320411618498470443e-43
    {    -0x1.773999999999ap+6, {   0x1.963d6d84352aap-136,  -0x1.1d71a6ab13e33p-191 }, 1 }, // exp(-93.80625) == 1.8216429483484996106e-41
    {    -0x1.6ad6666666666p+6, {   0x1.18ec7785c51ebp-131,  -0x1.7109acc332709p-185 }, 1 }, // exp(-90.709375) == 4.0310573842200973865e-40
    {    -0x1.5e73333333333p+6, {   0x1.848794544d2e2p-127,   0x1.1b07f6ef4eb6cp-182 }, 1 }, // exp(-87.6125) == 8.9202023094629276913e-39
    {    -0x1.5210000000000p+6, {   0x1.0cad367be74cap-122,  -0x1.58298449c3487p-179 }, 1 }, // exp(-84.515625) == 1.9739240020058021001e-37
    {    -0x1.45acccccccccdp+6, {   0x1.7397633d5b37cp-118,  -0x1.69a135887a227p-172 }, 1 }, // exp(-81.41875) == 4.3680354217540127743e-36
    {    -0x1.394999999999ap+6, {   0x1.00f6a4816604ep-113,  -0x1.8d53225c12f02p-167 }, 1 }, // exp(-78.321875) == 9.6658905947290233057e-35
    {    -0x1.2ce6666666666p+6, {   0x1.63643c4c10031p-109,   0x1.77637d267853fp-163 }, 1 }, // exp(-75.225) == 2.1389350581721044153e-33
    {    -0x1.2083333333333p+6, {   0x1.eb85983fc8faep-105,  -0x1.cba8e85bf56dfp-159 }, 1 }, // exp(-72.128125) == 4.7331832884312683656e-32
    {    -0x1.1420000000000p+6, {   0x1.53e5e1b8a8fdap-100,  -0x1.c1d54d300bed0p-154 }, 1 }, // exp(-69.03125) == 1.0473915024344057651e-30
    {    -0x1.07bcccccccccdp+6, {    0x1.d617f4c3f259ep-96,  -0x1.0b1ac9e6cd925p-150 }, 1 }, // exp(-65.934375) == 2.3177402870772686023e-29
    {    -0x1.f6b3333333334p+5, {    0x1.451471b5a17f4p-91,   0x1.091174fc68114p-145 }, 1 }, // exp(-62.837500000000006) == 5.1288558536662778103e-28
    {    -0x1.ddecccccccccdp+5, {    0x1.c19977d9ed3dfp-87,  -0x1.1c0f146c2c3f1p-141 }, 1 }, // exp(-59.740625) == 1.1349486616060219194e-26
    {    -0x1.c526666666667p+5, {    0x1.36e8626d2e741p-82,   0x1.ca2ba1ef919dbp-140 }, 1 }, // exp(-56.643750000000004) == 2.5114928187356021356e-25
    {    -0x1.ac60000000000p+5, {    0x1.adffb4761f3b2p-78,   0x1.e329cc63acd88p-132 }, 1 }, // exp(-53.546875) == 5.5576048432313314558e-24
    {    -0x1.939999999999ap+5, {    0x1.295a7e2b7a8d4p-73,   0x1.bc755390bbf0bp-127 }, 1 }, // exp(-50.45) == 1.2298252004980056599e-22
    {    -0x1.7ad3333333334p+5, {    0x1.9b40b1e8dbb6bp-69,   0x1.eb1ca93f43f84p-125 }, 1 }, // exp(-47.353125000000006) == 2.721442179578517225e-21
    {    -0x1.620cccccccccdp+5, {    0x1.1c63dfb3af7d6p-64,   0x1.953d3ed319d50p-118 }, 1 }, // exp(-44.25625) == 6.0221952955509739742e-20
    {    -0x1.4946666666667p+5, {    0x1.8952e6cbc3369p-60,   0x1.18a5e1d6e41eep-117 }, 1 }, // exp(-41.159375000000004) == 1.3326329859182546944e-18
    {    -0x1.3080000000000p+5, {    0x1.0ffdeebdee7cfp-55,   0x1.ed0ad81a3eadfp-111 }, 1 }, // exp(-38.0625) == 2.9489423507560572803e-17
    {    -0x1.17b999999999ap+5, {    0x1.782d3427bff0cp-51,  -0x1.c19c61c315a0ep-106 }, 1 }, // exp(-34.965625) == 6.5256233936685989058e-16
    {    -0x1.fde6666666668p+4, {    0x1.04225c9c6f487p-46,   0x1.c6fb9b1754d7bp-100 }, 1 }, // exp(-31.868750000000006) == 1.444035033953008602e-14
    {    -0x1.cc5999999999cp+4, {    0x1.67c6e0d127fb0p-42,    0x1.d5e61424ac7c0p-99 }, 1 }, // exp(-28.77187500000001) == 3.1954605000755037699e-13
    {    -0x1.9acccccccccd0p+4, {    0x1.f196420c215f0p-38,   -0x1.692eb8a812457p-95 }, 1 }, // exp(-25.67500000000001) == 7.0711357878835723488e-12
    {    -0x1.6940000000000p+4, {    0x1.581794f7a8b01p-33,    0x1.7575fae3fad9ap-89 }, 1 }, // exp(-22.578125) == 1.5647497858135656804e-10
    {    -0x1.37b3333333334p+4, {    0x1.dbe4ee09717f3p-29,   -0x1.6064476dccdd8p-86 }, 1 }, // exp(-19.481250000000003) == 3.462586443890644402e-9
    {    -0x1.0626666666668p+4, {    0x1.491755e7b92afp-24,    0x1.73bdd124c6f7fp-79 }, 1 }, // exp(-16.384375000000006) == 7.6622505336733531774e-8
    {    -0x1.a933333333338p+3, {    0x1.c725b40be9bd6p-20,   -0x1.26ad92979133dp-79 }, 1 }, // exp(-13.287500000000009) == 1.6955557411242429821e-6
    {    -0x1.46199999999a0p+3, {    0x1.3abe81fb6b81dp-15,    0x1.2a52caceace11p-70 }, 1 }, // exp(-10.190625000000011) == 0.00003752042899961302901
    {    -0x1.c600000000000p+2, {    0x1.b34e0618b78dap-11,   -0x1.d308c1bd3b7ccp-66 }, 1 }, // exp(-7.09375) == 0.00083027797799297838521
    {    -0x1.ff999999999a0p+1, {     0x1.2d05ccb88b9e2p-6,   -0x1.2270ab5eaabcbp-61 }, 1 }, // exp(-3.996875000000003) == 0.018372964785322915889
    {    -0x1.ccccccccccd00p-1, {     0x1.a053cc0086df4p-2,    0x1.9fc59d5c64550p-56 }, 1 }, // exp(-0.9000000000000057) == 0.4065696597405968008
    {    -0x1.0000000000000p+0, {     0x1.78b56362cef38p-2,   -0x1.ca8a4270fadf5p-57 }, 1 }, // exp(-1.0) == 0.3678794411714423216
    {    -0x1.e000000000000p-1, {     0x1.910110be06976p-2,    0x1.c14c2e7d1c9a4p-59 }, 1 }, // exp(-0.9375) == 0.39160562667679899323
    {    -0x1.c000000000000p-1, {     0x1.aadde095dad4bp-2,    0x1.00953b6ea1c60p-56 }, 1 }, // exp(-0.875) == 0.41686201967850840259
    {    -0x1.a000000000000p-1, {     0x1.c665b1e1f1e0dp-2,    0x1.066bfc732c207p-60 }, 1 }, // exp(-0.8125) == 0.44374731008107987185
    {    -0x1.8000000000000p-1, {     0x1.e3b40ebefcd7ep-2,    0x1.4bbf0f4cffc58p-56 }, 1 }, // exp(-0.75) == 0.47236655274101470714
    {    -0x1.6000000000000p-1, {     0x1.017323fd90020p-1,    0x1.b08c1550c28b5p-55 }, 1 }, // exp(-0.6875) == 0.50283157797094095969
    {    -0x1.4000000000000p-1, {     0x1.120dc934993e8p-1,   -0x1.5353ad174351dp-55 }, 1 }, // exp(-0.625) == 0.53526142851899024196
    {    -0x1.2000000000000p-1, {     0x1.23ba930c1568bp-1,   -0x1.b61343fc21a3bp-64 }, 1 }, // exp(-0.5625) == 0.56978282473092300977
    {    -0x1.0000000000000p-1, {     0x1.368b2fc6f960ap-1,   -0x1.85314b9559e64p-61 }, 1 }, // exp(-0.5) == 0.6065306597126334236
    {    -0x1.c000000000000p-2, {     0x1.4a9271936fd09p-1,   -0x1.4edd8a92eb584p-56 }, 1 }, // exp(-0.4375) == 0.64564852642789203735
    {    -0x1.8000000000000p-2, {     0x1.5fe4615e98e8fp-1,   -0x1.5613923fd9eeep-55 }, 1 }, // exp(-0.375) == 0.68728927879097219855
    {    -0x1.4000000000000p-2, {     0x1.769652df22f7ep-1,    0x1.3445f7544e0efp-57 }, 1 }, // exp(-0.3125) == 0.73161562894664179116
    {    -0x1.0000000000000p-2, {     0x1.8ebef9eac820bp-1,   -0x1.797d4686c5393p-57 }, 1 }, // exp(-0.25) == 0.77880078307140486825
    {    -0x1.8000000000000p-3, {     0x1.a876812c0877cp-1,   -0x1.fd36226fadd44p-56 }, 1 }, // exp(-0.1875) == 0.82902911818040034301
    {    -0x1.0000000000000p-3, {     0x1.c3d6a24ed8222p-1,   -0x1.e1e0a76cb0685p-55 }, 1 }, // exp(-0.125) == 0.88249690258459540286
    {    -0x1.0000000000000p-4, {     0x1.e0fabfbc702a4p-1,   -0x1.8d0e700fcfb65p-56 }, 1 }, // exp(-0.0625) == 0.93941306281347578612
    {                 0x0.0p+0, {     0x1.0000000000000p+0,                 0x0.0p+0 }, 1 }, // exp(0.0) == 1.0
    {     0x1.0000000000000p-4, {     0x1.1082b577d34edp+0,    0x1.f56c680678897p-54 }, 1 }, // exp(0.0625) == 1.0644944589178594296
    {     0x1.0000000000000p-3, {     0x1.2216045b6f5cdp+0,   -0x1.8c4a5df1ec7e5p-58 }, 1 }, // exp(0.125) == 1.1331484530668263168
    {     0x1.8000000000000p-3, {     0x1.34cb8170b5835p+0,    0x1.6a7062465be33p-55 }, 1 }, // exp(0.1875) == 1.2062302494209807107
    {     0x1.0000000000000p-2, {     0x1.48b5e3c3e8186p+0,    0x1.9d9ef0eda6eabp-54 }, 1 }, // exp(0.25) == 1.2840254166877414841
    {     0x1.4000000000000p-2, {     0x1.5de9176045ff5p+0,    0x1.da89923298baap-55 }, 1 }, // exp(0.3125) == 1.3668379411737963628
    {     0x1.8000000000000p-2, {     0x1.747a513dbef6ap+0,    0x1.88d1e2d966c25p-54 }, 1 }, // exp(0.375) == 1.4549914146182013361
    {     0x1.c000000000000p-2, {     0x1.8c802477b0010p+0,   -0x1.1ed925f893d67p-55 }, 1 }, // exp(0.4375) == 1.548830298634133098
    {     0x1.0000000000000p-1, {     0x1.a61298e1e069cp+0,   -0x1.b4690082a4906p-55 }, 1 }, // exp(0.5) == 1.6487212707001281468
    {     0x1.2000000000000p-1, {     0x1.c14b431256446p+0,    0x1.10caa944ee909p-54 }, 1 }, // exp(0.5625) == 1.7550546569602985572
    {     0x1.4000000000000p-1, {     0x1.de455df80e3c0p+0,    0x1.72a25ec1cbdb7p-54 }, 1 }, // exp(0.625) == 1.8682459574322224065
    {     0x1.6000000000000p-1, {     0x1.fd1de6182f8c9p+0,   -0x1.8b4f124bdce6ap-54 }, 1 }, // exp(0.6875) == 1.9887374695822918311
    {     0x1.8000000000000p-1, {     0x1.0ef9db467dcf8p+1,   -0x1.0acf2a4470462p-53 }, 1 }, // exp(0.75) == 2.1170000166126746685
    {     0x1.a000000000000p-1, {     0x1.2073d3f1bd518p+1,   -0x1.bb8b0f3c94f34p-61 }, 1 }, // exp(0.8125) == 2.2535347872132085449
    {     0x1.c000000000000p-1, {     0x1.330e587b62b28p+1,   -0x1.8f77802a131bdp-53 }, 1 }, // exp(0.875) == 2.3988752939670979147
    {     0x1.e000000000000p-1, {     0x1.46dc04f4e5338p+1,    0x1.2896ff654d054p-54 }, 1 }, // exp(0.9375) == 2.5535894580629268734
    {     0x1.0000000000000p+0, {     0x1.5bf0a8b145769p+1,    0x1.4d57ee2b1013ap-53 }, 1 }, // exp(1.0) == 2.7182818284590452354
    {     0x1.199999999999ap+0, {     0x1.808883244d593p+1,   -0x1.2598b56c7967ep-56 }, 1 }, // exp(1.1) == 3.0041660239464333789
    {     0x1.0c33333333334p+2, {     0x1.08419b1194387p+6,   -0x1.28bdda5c25fb5p-52 }, 1 }, // exp(4.190625000000001) == 66.06406810252347813
    {     0x1.d200000000000p+2, {    0x1.6b33629e5db4fp+10,    0x1.a01a35ad61ac2p-44 }, 1 }, // exp(7.28125) == 1452.8028942027193367
    {     0x1.4be6666666667p+3, {    0x1.f3314bba61537p+14,   -0x1.cda465bdffd13p-42 }, 1 }, // exp(10.371875000000001) == 31948.323953171460334
    {     0x1.aeccccccccccdp+3, {    0x1.570d38d1f922cp+19,    0x1.307073de98a40p-36 }, 1 }, // exp(13.4625) == 702569.77563149250912
    {     0x1.08d999999999ap+4, {    0x1.d77fc80e5891dp+23,   -0x1.888be9d9e4d38p-31 }, 1 }, // exp(16.553125) == 15450084.028019481556
    {     0x1.3a4cccccccccep+4, {    0x1.44053710f9d6dp+28,   -0x1.7a59658aa2e2dp-27 }, 1 }, // exp(19.643750000000004) == 339759985.06099586578
    {     0x1.6bc0000000001p+4, {    0x1.bd579167b8bdbp+32,   -0x1.382629f2cf0c5p-25 }, 1 }, // exp(22.734375000000004) == 7471599975.7216443652
    {     0x1.9d33333333334p+4, {    0x1.320b7d5fbba1dp+37,    0x1.07bec0c194157p-18 }, 1 }, // exp(25.825000000000003) == 164306594807.45401394
    {     0x1.cea6666666667p+4, {    0x1.a4a2d6218d4cbp+41,    0x1.430fbeda0e00fp-14 }, 1 }, // exp(28.915625000000002) == 3613236413210.5991981
    {     0x1.000cccccccccdp+5, {    0x1.21110d3723a14p+46,     0x1.3afb23a172798p-8 }, 1 }, // exp(32.00625) == 79458024147176.317306
    {     0x1.18c6666666667p+5, {    0x1.8d4cfa75ff2ecp+50,     0x1.13ca9823df99ap-7 }, 1 }, // exp(35.096875000000004) == 1747346943114427.0084
    {     0x1.3180000000001p+5, {    0x1.1107bd02b81bfp+55,     0x1.c0e249d827ca2p+1 }, 1 }, // exp(38.18750000000001) == 38425588508921339.507
    {     0x1.4a3999999999ap+5, {    0x1.7742874d8bfebp+59,     0x1.f5e3df4a8cc0cp+3 }, 1 }, // exp(41.278125) == 845010121244276111.68
    {     0x1.62f3333333334p+5, {    0x1.01e22c5059b99p+64,    0x1.dd508cfb98174p+10 }, 1 }, // exp(44.368750000000006) == 18582463736098428789.0
    {     0x1.7bacccccccccdp+5, {    0x1.62711a0261115p+68,   -0x1.f337f78939cefp+13 }, 1 }, // exp(47.459375) == 4.0864357694904918057e+20
    {     0x1.9466666666667p+5, {    0x1.e727714f86eedp+72,    0x1.476843dba1028p+18 }, 1 }, // exp(50.550000000000004) == 8.9864065041773502868e+21
    {     0x1.ad20000000001p+5, {    0x1.4ec7550a4ef7fp+77,   -0x1.b067abcb4cae2p+22 }, 1 }, // exp(53.64062500000001) == 1.9761842939327492836e+23
    {     0x1.c5d999999999ap+5, {    0x1.cc20e60104e15p+81,   -0x1.25db494fabb28p+27 }, 1 }, // exp(56.73125) == 4.3457909029277297668e+24
    {     0x1.de93333333334p+5, {    0x1.3c34d17a8a978p+86,   -0x1.30b5cf88ba71fp+30 }, 1 }, // exp(59.821875000000006) == 9.5567496563720009092e+25
    {     0x1.f74cccccccccdp+5, {    0x1.b29a2b9b36175p+90,   -0x1.3efaaf804101bp+34 }, 1 }, // exp(62.9125) == 2.1016074181810340333e+27
    {     0x1.0803333333333p+6, {    0x1.2aaa115926b44p+95,   -0x1.23fd60c691bd9p+41 }, 1 }, // exp(66.003125) == 4.6216066120437334103e+28
    {     0x1.1460000000000p+6, {    0x1.9a7df72d1b921p+99,   -0x1.3a1b530dafa4cp+42 }, 1 }, // exp(69.09375) == 1.01632909608651781e+30
    {     0x1.20bcccccccccdp+6, {   0x1.1a1872b0dc2d0p+104,   -0x1.1b5844714abb3p+50 }, 1 }, // exp(72.184375) == 2.2349908121999717578e+31
    {     0x1.2d1999999999ap+6, {   0x1.83b82c2bc7dfep+108,   -0x1.32c0cad016636p+54 }, 1 }, // exp(75.275) == 4.9149276054899648902e+32
    {     0x1.3976666666666p+6, {   0x1.0a72235c594f4p+113,    0x1.bcd1eafb3751ap+57 }, 1 }, // exp(78.365625) == 1.0808327817432484531e+34
    {     0x1.45d3333333333p+6, {   0x1.6e35cbabb74e5p+117,    0x1.58807dadc1779p+62 }, 1 }, // exp(81.45625) == 2.3768396929915885258e+35
    {     0x1.5230000000000p+6, {   0x1.f7542afdd43c8p+121,    0x1.0ffa4a976b686p+67 }, 1 }, // exp(84.546875) == 5.2268648967776723534e+36
    {     0x1.5e8cccccccccdp+6, {   0x1.59e4e48868d5dp+126,    0x1.f8cc5fe3c01d1p+71 }, 1 }, // exp(87.6375) == 1.1494303435660164862e+38
    {     0x1.6ae999999999ap+6, {   0x1.db67e941b66f0p+130,   -0x1.daaf33e2b4f6fp+75 }, 1 }, // exp(90.728125) == 2.5276913423279711447e+39
    {     0x1.7746666666666p+6, {   0x1.46b4846cff9b7p+135,    0x1.9e31f91008987p+75 }, 1 }, // exp(93.81875) == 5.5586000124702037439e+40
    {     0x1.83a3333333333p+6, {   0x1.c10836cd04f0dp+139,    0x1.b2789fd950754p+84 }, 1 }, // exp(96.909375) == 1.2223816089102673893e+42
    {     0x1.9000000000000p+6, {   0x1.3494a9b171bf5p+144,   -0x1.4cf76bdb3376fp+90 }, 1 }, // exp(100.0) == 2.6881171418161354484e+43
};

void Test_exp_approx(void)
{
    for (int i = 0; i < _countof(s_exp_approx_tests); i++)
    {
        double x = s_exp_approx_tests[i].x;
        double expected = s_exp_approx_tests[i].expected.rounded;
        double z = exp(x);
        int64_t error = abs(ulp_error_precise(&s_exp_approx_tests[i].expected, z));
        ok(error <= s_exp_approx_tests[i].max_error,
            "exp(%.17e) = %.17e, expected %.17e, error %I64d ULPs, max %u ULPs\n",
            x, z, expected, error, s_exp_approx_tests[i].max_error);
    }
}

#if defined(HAS_EXPF)

// These are expected to match exactly
static TESTENTRY_DBL s_expf_exact_tests[] =
{
    { 0x00000000 /*  0.000000 */, 0x3f800000 /*  1.000000 */ },
    { 0x80000000 /* -0.000000 */, 0x3f800000 /*  1.000000 */ },
    { 0x7f800000 /*  1.#INF00 */, 0x3f800000 /*  1.000000 */ },
    { 0x7f800001 /*  1.#SNAN0 */, 0x3f800000 /*  1.000000 */ },
    { 0x7fBFffff /*  1.#SNAN0 */, 0x3f800000 /*  1.000000 */ },
    { 0x7fC00000 /*  1.#QNAN0 */, 0x3f800000 /*  1.000000 */ },
    { 0x7fC80001 /*  1.#QNAN0 */, 0x3f800000 /*  1.000000 */ },
    { 0x7fFfffff /*  1.#QNAN0 */, 0x3f800000 /*  1.000000 */ },
    { 0xff800000 /* -1.#INF00 */, 0x3f800000 /*  1.000000 */ },
    { 0xff800001 /* -1.#SNAN0 */, 0x3f800000 /*  1.000000 */ },
    { 0xffBfffff /* -1.#SNAN0 */, 0x3f800000 /*  1.000000 */ },
    { 0xffC00000 /* -1.#IND00 */, 0x3f800000 /*  1.000000 */ },
    { 0xfff80001 /* -1.#QNAN0 */, 0x3f800000 /*  1.000000 */ },
    { 0xffffffff /* -1.#QNAN0 */, 0x3f800000 /*  1.000000 */ },
};

void Test_expf_exact(void)
{
    for (int i = 0; i < _countof(s_expf_exact_tests); i++)
    {
        float x = u64_to_dbl(s_expf_exact_tests[i].x);
        float z = expf(x);
        ok_eq_flt_exact("expf", s_expf_exact_tests[i].x, z, s_expf_exact_tests[i].result);
    }
}

#endif // defined(HAS_EXPF)

#if defined(HAS_EXPF) || defined(HAS_LIBM_SSE2)

static TESTENTRY_DBL_APPROX s_expf_approx_tests[] =
{
//  {    x,                     {    y_rounded,               y_difference           } }
    {    -0x1.9000000000000p+6, {   0x1.a8c1f14e2af5dp-145,  -0x1.43089bb228e2cp-199 }, 1 }, // expf(-100.0) == 3.720075976020835963e-44
    {    -0x1.839ccc0000000p+6, {   0x1.25badd5d4f22dp-140,   0x1.ac004805b602cp-195 }, 1 }, // expf(-96.90312194824219) == 8.2320662840841324059e-43
    {    -0x1.77399a0000000p+6, {   0x1.963d44e4790e5p-136,   0x1.235837660a1b4p-191 }, 1 }, // expf(-93.8062515258789) == 1.8216401687440810318e-41
    {    -0x1.6ad6660000000p+6, {   0x1.18ec939d6c11ep-131,  -0x1.9bc098e45510ap-187 }, 1 }, // expf(-90.7093734741211) == 4.0310635351301997081e-40
    {    -0x1.5e73340000000p+6, {   0x1.8487469f9dae2p-127,   0x1.ec0171f118ccap-184 }, 1 }, // expf(-87.61250305175781) == 8.9201750872073532413e-39
    {    -0x1.5210000000000p+6, {   0x1.0cad367be74cap-122,  -0x1.58298449c3487p-179 }, 1 }, // expf(-84.515625) == 1.9739240020058021001e-37
    {    -0x1.45accc0000000p+6, {   0x1.7397ad8edce6fp-118,  -0x1.c0cfd21705ba8p-172 }, 1 }, // expf(-81.41874694824219) == 4.3680487519605890743e-36
    {    -0x1.39499a0000000p+6, {   0x1.00f68acf23a8dp-113,   0x1.1e1c9746126f3p-167 }, 1 }, // expf(-78.3218765258789) == 9.6658758457617622044e-35
    {    -0x1.2ce6660000000p+6, {   0x1.63645fd617cf6p-109,  -0x1.99959f4db51cdp-166 }, 1 }, // expf(-75.2249984741211) == 2.1389383219304694097e-33
    {    -0x1.2083340000000p+6, {   0x1.eb8535f1e78dfp-105,   0x1.79a558e4aa5c6p-161 }, 1 }, // expf(-72.12812805175781) == 4.7331688439242170284e-32
    {    -0x1.1420000000000p+6, {   0x1.53e5e1b8a8fdap-100,  -0x1.c1d54d300bed0p-154 }, 1 }, // expf(-69.03125) == 1.0473915024344057651e-30
    {    -0x1.07bccc0000000p+6, {    0x1.d61852c8c64fdp-96,  -0x1.c5c9051cf6091p-151 }, 1 }, // expf(-65.93437194824219) == 2.317747360270096454e-29
    {    -0x1.f6b3340000000p+5, {    0x1.4514513397c27p-91,  -0x1.5558976346e56p-150 }, 1 }, // expf(-62.837501525878906) == 5.1288480276593174292e-28
    {    -0x1.ddeccc0000000p+5, {    0x1.c199a4cfaead8p-87,   0x1.852207a797e16p-144 }, 1 }, // expf(-59.740623474121094) == 1.1349503934015672084e-26
    {    -0x1.c526660000000p+5, {    0x1.36e871f8cd5e8p-82,  -0x1.d7bb37d4ca479p-136 }, 1 }, // expf(-56.64374923706055) == 2.511494734853301437e-25
    {    -0x1.ac60000000000p+5, {    0x1.adffb4761f3b2p-78,   0x1.e329cc63acd88p-132 }, 1 }, // expf(-53.546875) == 5.5576048432313314558e-24
    {    -0x1.93999a0000000p+5, {    0x1.295a6f4d5b04dp-73,  -0x1.ba29e0d7709d2p-127 }, 1 }, // expf(-50.45000076293945) == 1.2298242622162011742e-22
    {    -0x1.7ad3340000000p+5, {    0x1.9b4088c8cbfd3p-69,  -0x1.3a866e88d4cbbp-125 }, 1 }, // expf(-47.353126525878906) == 2.7214380269904844707e-21
    {    -0x1.620ccc0000000p+5, {    0x1.1c63fc2414157p-64,  -0x1.5b658d32bbbc5p-120 }, 1 }, // expf(-44.256248474121094) == 6.0222044846987640931e-20
    {    -0x1.4946660000000p+5, {    0x1.8952fa764f407p-60,   0x1.72d83c80633cdp-114 }, 1 }, // expf(-41.15937423706055) == 1.3326340026369297159e-18
    {    -0x1.3080000000000p+5, {    0x1.0ffdeebdee7cfp-55,   0x1.ed0ad81a3eadfp-111 }, 1 }, // expf(-38.0625) == 2.9489423507560572803e-17
    {    -0x1.17b99a0000000p+5, {    0x1.782d2158b101ep-51,   0x1.a6f6573549e0cp-105 }, 1 }, // expf(-34.96562576293945) == 6.5256184150149733933e-16
    {    -0x1.fde6660000000p+4, {    0x1.0422631d4b493p-46,   0x1.9d2a8b356dc3bp-100 }, 1 }, // expf(-31.868749618530273) == 1.4440355848087714266e-14
    {    -0x1.cc599a0000000p+4, {    0x1.67c6d7d295af8p-42,    0x1.e72699ad6e604p-96 }, 1 }, // expf(-28.771875381469727) == 3.1954592811043203113e-13
    {    -0x1.9acccc0000000p+4, {    0x1.f1965aed3eeb7p-38,    0x1.c9a97de44503fp-93 }, 1 }, // expf(-25.674999237060547) == 7.0711411827341816908e-12
    {    -0x1.6940000000000p+4, {    0x1.581794f7a8b01p-33,    0x1.7575fae3fad9ap-89 }, 1 }, // expf(-22.578125) == 1.5647497858135656804e-10
    {    -0x1.37b3340000000p+4, {    0x1.dbe4d63dffcbbp-29,   -0x1.99f7b1d05901dp-87 }, 1 }, // expf(-19.481250762939453) == 3.4625838021478540883e-9
    {    -0x1.0626660000000p+4, {    0x1.49175e21e839fp-24,   -0x1.7766cf34287e1p-79 }, 1 }, // expf(-16.384374618530273) == 7.6622534565905701682e-8
    {    -0x1.a933340000000p+3, {    0x1.c725a8aaf898fp-20,    0x1.252b093ebf5bcp-74 }, 1 }, // expf(-13.287500381469727) == 1.695555094321195869e-6
    {    -0x1.46199a0000000p+3, {    0x1.3abe7e0c3d1f5p-15,   -0x1.2458d15f428cfp-71 }, 1 }, // expf(-10.190625190734863) == 0.000037520421843160242565
    {    -0x1.c600000000000p+2, {    0x1.b34e0618b78dap-11,   -0x1.d308c1bd3b7ccp-66 }, 1 }, // expf(-7.09375) == 0.00083027797799297838521
    {    -0x1.ff999a0000000p+1, {     0x1.2d05cbc7ba2eep-6,   -0x1.30a3f824d11adp-60 }, 1 }, // expf(-3.996875047683716) == 0.018372963909231757396
    {    -0x1.cccccc0000000p-1, {     0x1.a053cca70ecd3p-2,    0x1.55932aea16ebep-56 }, 1 }, // expf(-0.8999999761581421) == 0.40656966943397528555
    {    -0x1.0000000000000p+0, {     0x1.78b56362cef38p-2,   -0x1.ca8a4270fadf5p-57 }, 1 }, // expf(-1.0) == 0.3678794411714423216
    {    -0x1.e000000000000p-1, {     0x1.910110be06976p-2,    0x1.c14c2e7d1c9a4p-59 }, 1 }, // expf(-0.9375) == 0.39160562667679899323
    {    -0x1.c000000000000p-1, {     0x1.aadde095dad4bp-2,    0x1.00953b6ea1c60p-56 }, 1 }, // expf(-0.875) == 0.41686201967850840259
    {    -0x1.a000000000000p-1, {     0x1.c665b1e1f1e0dp-2,    0x1.066bfc732c207p-60 }, 1 }, // expf(-0.8125) == 0.44374731008107987185
    {    -0x1.8000000000000p-1, {     0x1.e3b40ebefcd7ep-2,    0x1.4bbf0f4cffc58p-56 }, 1 }, // expf(-0.75) == 0.47236655274101470714
    {    -0x1.6000000000000p-1, {     0x1.017323fd90020p-1,    0x1.b08c1550c28b5p-55 }, 1 }, // expf(-0.6875) == 0.50283157797094095969
    {    -0x1.4000000000000p-1, {     0x1.120dc934993e8p-1,   -0x1.5353ad174351dp-55 }, 1 }, // expf(-0.625) == 0.53526142851899024196
    {    -0x1.2000000000000p-1, {     0x1.23ba930c1568bp-1,   -0x1.b61343fc21a3bp-64 }, 1 }, // expf(-0.5625) == 0.56978282473092300977
    {    -0x1.0000000000000p-1, {     0x1.368b2fc6f960ap-1,   -0x1.85314b9559e64p-61 }, 1 }, // expf(-0.5) == 0.6065306597126334236
    {    -0x1.c000000000000p-2, {     0x1.4a9271936fd09p-1,   -0x1.4edd8a92eb584p-56 }, 1 }, // expf(-0.4375) == 0.64564852642789203735
    {    -0x1.8000000000000p-2, {     0x1.5fe4615e98e8fp-1,   -0x1.5613923fd9eeep-55 }, 1 }, // expf(-0.375) == 0.68728927879097219855
    {    -0x1.4000000000000p-2, {     0x1.769652df22f7ep-1,    0x1.3445f7544e0efp-57 }, 1 }, // expf(-0.3125) == 0.73161562894664179116
    {    -0x1.0000000000000p-2, {     0x1.8ebef9eac820bp-1,   -0x1.797d4686c5393p-57 }, 1 }, // expf(-0.25) == 0.77880078307140486825
    {    -0x1.8000000000000p-3, {     0x1.a876812c0877cp-1,   -0x1.fd36226fadd44p-56 }, 1 }, // expf(-0.1875) == 0.82902911818040034301
    {    -0x1.0000000000000p-3, {     0x1.c3d6a24ed8222p-1,   -0x1.e1e0a76cb0685p-55 }, 1 }, // expf(-0.125) == 0.88249690258459540286
    {    -0x1.0000000000000p-4, {     0x1.e0fabfbc702a4p-1,   -0x1.8d0e700fcfb65p-56 }, 1 }, // expf(-0.0625) == 0.93941306281347578612
    {                 0x0.0p+0, {     0x1.0000000000000p+0,                 0x0.0p+0 }, 1 }, // expf(0.0) == 1.0
    {     0x1.0000000000000p-4, {     0x1.1082b577d34edp+0,    0x1.f56c680678897p-54 }, 1 }, // expf(0.0625) == 1.0644944589178594296
    {     0x1.0000000000000p-3, {     0x1.2216045b6f5cdp+0,   -0x1.8c4a5df1ec7e5p-58 }, 1 }, // expf(0.125) == 1.1331484530668263168
    {     0x1.8000000000000p-3, {     0x1.34cb8170b5835p+0,    0x1.6a7062465be33p-55 }, 1 }, // expf(0.1875) == 1.2062302494209807107
    {     0x1.0000000000000p-2, {     0x1.48b5e3c3e8186p+0,    0x1.9d9ef0eda6eabp-54 }, 1 }, // expf(0.25) == 1.2840254166877414841
    {     0x1.4000000000000p-2, {     0x1.5de9176045ff5p+0,    0x1.da89923298baap-55 }, 1 }, // expf(0.3125) == 1.3668379411737963628
    {     0x1.8000000000000p-2, {     0x1.747a513dbef6ap+0,    0x1.88d1e2d966c25p-54 }, 1 }, // expf(0.375) == 1.4549914146182013361
    {     0x1.c000000000000p-2, {     0x1.8c802477b0010p+0,   -0x1.1ed925f893d67p-55 }, 1 }, // expf(0.4375) == 1.548830298634133098
    {     0x1.0000000000000p-1, {     0x1.a61298e1e069cp+0,   -0x1.b4690082a4906p-55 }, 1 }, // expf(0.5) == 1.6487212707001281468
    {     0x1.2000000000000p-1, {     0x1.c14b431256446p+0,    0x1.10caa944ee909p-54 }, 1 }, // expf(0.5625) == 1.7550546569602985572
    {     0x1.4000000000000p-1, {     0x1.de455df80e3c0p+0,    0x1.72a25ec1cbdb7p-54 }, 1 }, // expf(0.625) == 1.8682459574322224065
    {     0x1.6000000000000p-1, {     0x1.fd1de6182f8c9p+0,   -0x1.8b4f124bdce6ap-54 }, 1 }, // expf(0.6875) == 1.9887374695822918311
    {     0x1.8000000000000p-1, {     0x1.0ef9db467dcf8p+1,   -0x1.0acf2a4470462p-53 }, 1 }, // expf(0.75) == 2.1170000166126746685
    {     0x1.a000000000000p-1, {     0x1.2073d3f1bd518p+1,   -0x1.bb8b0f3c94f34p-61 }, 1 }, // expf(0.8125) == 2.2535347872132085449
    {     0x1.c000000000000p-1, {     0x1.330e587b62b28p+1,   -0x1.8f77802a131bdp-53 }, 1 }, // expf(0.875) == 2.3988752939670979147
    {     0x1.e000000000000p-1, {     0x1.46dc04f4e5338p+1,    0x1.2896ff654d054p-54 }, 1 }, // expf(0.9375) == 2.5535894580629268734
    {     0x1.0000000000000p+0, {     0x1.5bf0a8b145769p+1,    0x1.4d57ee2b1013ap-53 }, 1 }, // expf(1.0) == 2.7182818284590452354
    {     0x1.19999a0000000p+0, {     0x1.808883be1d8dcp+1,   -0x1.a0352aa6edc6dp-53 }, 1 }, // expf(1.100000023841858) == 3.0041660955713334473
    {     0x1.0c33340000000p+2, {     0x1.08419e5f32fa9p+6,   -0x1.c6266b0530320p-48 }, 1 }, // expf(4.190625190734863) == 66.064080703245630225
    {     0x1.d200000000000p+2, {    0x1.6b33629e5db4fp+10,    0x1.a01a35ad61ac2p-44 }, 1 }, // expf(7.28125) == 1452.8028942027193367
    {     0x1.4be6660000000p+3, {    0x1.f331457cf6d0ep+14,    0x1.92710de08fc22p-40 }, 1 }, // expf(10.371874809265137) == 31948.317859512806146
    {     0x1.aecccc0000000p+3, {    0x1.570d303e716c0p+19,    0x1.4912686eb5bd2p-35 }, 1 }, // expf(13.462499618530273) == 702569.50762244317696
    {     0x1.08d99a0000000p+4, {    0x1.d77fd3d7f0ea5p+23,    0x1.256bed94ba80bp-31 }, 1 }, // expf(16.553125381469727) == 15450089.921759913278
    {     0x1.3a4ccc0000000p+4, {    0x1.440526dd8448fp+28,   -0x1.21e9711b4c31dp-26 }, 1 }, // expf(19.643749237060547) == 339759725.84479610425
    {     0x1.6bc0000000000p+4, {    0x1.bd579167b8bbfp+32,    0x1.062dc1a6edd49p-23 }, 1 }, // expf(22.734375) == 7471599975.7216178208
    {     0x1.9d33340000000p+4, {    0x1.320b8cad1be13p+37,   -0x1.2e8868843d1b2p-20 }, 1 }, // expf(25.825000762939453) == 164306720163.48495371
    {     0x1.cea6660000000p+4, {    0x1.a4a2cb9d7b462p+41,   -0x1.750bdcbbe3465p-17 }, 1 }, // expf(28.915624618530273) == 3613235034870.5478404
    {     0x1.000ccc0000000p+5, {    0x1.2110f04f0a26fp+46,    -0x1.d7add59e2212ap-8 }, 1 }, // expf(32.006248474121094) == 79457902903945.727178
    {     0x1.18c6660000000p+5, {    0x1.8d4ce6988cbfcp+50,    -0x1.876efe5083897p-4 }, 1 }, // expf(35.09687423706055) == 1747345609995006.9044
    {     0x1.3180000000000p+5, {    0x1.1107bd02b819dp+55,     0x1.3d03c87c1a572p+1 }, 1 }, // expf(38.1875) == 38425588508921066.477
    {     0x1.4a399a0000000p+5, {    0x1.77429a10e0065p+59,    -0x1.e34272b96e6fbp+5 }, 1 }, // expf(41.27812576293945) == 845010765936079427.59
    {     0x1.62f3340000000p+5, {    0x1.01e2461a2c3d5p+64,    -0x1.addb07a342dc8p+8 }, 1 }, // expf(44.368751525878906) == 18582492090709397074.0
    {     0x1.7baccc0000000p+5, {    0x1.6270f690ad096p+68,    0x1.030b511a4a0f6p+14 }, 1 }, // expf(47.459373474121094) == 4.0864295340891008224e+20
    {     0x1.9466660000000p+5, {    0x1.e72758f3f5114p+72,    0x1.84a03b2433d1ep+17 }, 1 }, // expf(50.54999923706055) == 8.9863996480958635073e+21
    {     0x1.ad20000000000p+5, {    0x1.4ec7550a4ef55p+77,   -0x1.def2d8690d2ffp+20 }, 1 }, // expf(53.640625) == 1.976184293932735242e+23
    {     0x1.c5d99a0000000p+5, {    0x1.cc20fd02aa8ccp+81,   -0x1.4107274dfee1cp+23 }, 1 }, // expf(56.73125076293945) == 4.3457942185043170825e+24
    {     0x1.de93340000000p+5, {    0x1.3c34f1196de9bp+86,    0x1.eb662f7afe196p+32 }, 1 }, // expf(59.821876525878906) == 9.5567642388257850818e+25
    {     0x1.f74ccc0000000p+5, {    0x1.b29a00256719dp+90,   -0x1.dae60a8bd9defp+35 }, 1 }, // expf(62.912498474121094) == 2.1016042113850490176e+27
    {     0x1.0803340000000p+6, {    0x1.2aaa4d14c9c03p+95,   -0x1.d8960cb4432efp+41 }, 1 }, // expf(66.00312805175781) == 4.6216207160893522066e+28
    {     0x1.1460000000000p+6, {    0x1.9a7df72d1b921p+99,   -0x1.3a1b530dafa4cp+42 }, 1 }, // expf(69.09375) == 1.01632909608651781e+30
    {     0x1.20bccc0000000p+6, {   0x1.1a183a4597ad1p+104,   -0x1.801bf0a66b617p+48 }, 1 }, // expf(72.18437194824219) == 2.234983991559700885e+31
    {     0x1.2d199a0000000p+6, {   0x1.83b852f167d21p+108,    0x1.e6e774183b841p+54 }, 1 }, // expf(75.2750015258789) == 4.9149351050800176467e+32
    {     0x1.3976660000000p+6, {   0x1.0a7208b7571ccp+113,   -0x1.92fa99cc85615p+58 }, 1 }, // expf(78.3656234741211) == 1.0808311325245700057e+34
    {     0x1.45d3340000000p+6, {   0x1.6e3614e9b42b3p+117,    0x1.574081ffbe583p+63 }, 1 }, // expf(81.45625305175781) == 2.376846946541765462e+35
    {     0x1.5230000000000p+6, {   0x1.f7542afdd43c8p+121,    0x1.0ffa4a976b686p+67 }, 1 }, // expf(84.546875) == 5.2268648967776723534e+36
    {     0x1.5e8ccc0000000p+6, {   0x1.59e49f5aa8714p+126,   -0x1.225786a363ff8p+71 }, 1 }, // expf(87.63749694824219) == 1.1494268357883347638e+38
    {     0x1.6ae99a0000000p+6, {   0x1.db6818cc1cecbp+130,    0x1.247782b779c0dp+76 }, 1 }, // expf(90.7281265258789) == 2.527695199281800167e+39
    {     0x1.7746660000000p+6, {   0x1.46b463c15a67fp+135,    0x1.96c0cc2320e51p+81 }, 1 }, // expf(93.8187484741211) == 5.5585915307261990903e+40
    {     0x1.83a3340000000p+6, {   0x1.c108909b7f498p+139,   -0x1.50633a93487f5p+85 }, 1 }, // expf(96.90937805175781) == 1.2223853393285878755e+42
    {     0x1.9000000000000p+6, {   0x1.3494a9b171bf5p+144,   -0x1.4cf76bdb3376fp+90 }, 1 }, // expf(100.0) == 2.6881171418161354484e+43
};

#endif // defined(HAS_EXPF) || defined(HAS_LIBM_SSE2)

#if defined(HAS_EXPF)

void Test_expf_approx(void)
{
    for (int i = 0; i < _countof(s_expf_approx_tests); i++)
    {
        float x = s_expf_approx_tests[i].x;
        float expected = s_expf_approx_tests[i].expected.rounded;
        float z = expf(x);
        int64_t error = abs(ulp_error_flt(expected, z));
        ok(error <= s_exp_approx_tests[i].max_error,
            "exp(%.6e) = %.7e, expected %.7e, error %I64d ULPs, max %u ULPs\n",
            x, z, expected, error, s_exp_approx_tests[i].max_error);
    }
}

#endif // defined(HAS_EXPF)

#if defined(HAS_LIBM_SSE2)

__ATTRIBUTE_SSE2__ __m128d __libm_sse2_exp(__m128d Xmm0);

__ATTRIBUTE_SSE2__
void Test_libm_sse2_exp(void)
{
    int i;
    for (i = 0; i < _countof(s_exp_approx_tests); i++)
    {
        double x = s_exp_approx_tests[i].x;
        double expected = s_exp_approx_tests[i].expected.rounded;
        __m128d xmm0 = _mm_set_sd(x);
        __m128d xmm1 = __libm_sse2_exp(xmm0);
        double z = _mm_cvtsd_f64(xmm1);
        int64_t error = ulp_error_precise(&s_exp_approx_tests[i].expected, z);
        ok(error <= s_exp_approx_tests[i].max_error,
            "__libm_sse2_exp(%.17e) = %.17e, expected %.17e, error %I64d ULPs, max %u ULPs\n",
            x, z, expected, error, s_exp_approx_tests[i].max_error);
    }
}

__ATTRIBUTE_SSE2__ __m128 __libm_sse2_expf(__m128 Xmm0);

__ATTRIBUTE_SSE2__
void Test_libm_sse2_expf(void)
{
    int i;
    for (i = 0; i < _countof(s_expf_approx_tests); i++)
    {
        float x = s_expf_approx_tests[i].x;
        float expected = s_expf_approx_tests[i].expected.rounded;
        __m128 xmm0 = _mm_set_ps1(x);
        __m128 xmm1 = __libm_sse2_expf(xmm0);
        float z = _mm_cvtss_f32(xmm1);
        int64_t error = ulp_error_flt(expected, z);
        ok(error <= s_expf_approx_tests[i].max_error,
            "__libm_sse2_expf(%.6e) = %.7e, expected %.7e, error %I64d ULPs, max %u ULPs\n",
            x, z, expected, error, s_expf_approx_tests[i].max_error);
    }
}

#endif // defined(HAS_LIBM_SSE2)

START_TEST(exp)
{
    Test_exp_exact();
    Test_exp_approx();
#if defined(HAS_EXPF)
    Test_expf_exact();
    Test_expf_approx();
#endif
#if defined(HAS_LIBM_SSE2)
    Test_libm_sse2_exp();
    Test_libm_sse2_expf();
#endif
}
